package it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyScrollPanel;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventPreview;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseWheelHandler;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseWheelListener;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FResizePoller;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyPNGImage.FPNGImage;

public class FScrollPanel extends Composite {
    private AbsolutePanel parent;
    private AbsolutePanel viewPort;
    private Widget child;
    private VBar vBar;
    private HBar hBar;
    private FPNGImage square;
    private boolean hasVCursorFixedHeight = false;
    private boolean hasHCursorFixedWidth = false;

    public FScrollPanel(Widget w) {

        parent = new AbsolutePanel();
        viewPort = new AbsolutePanel();
        viewPort.setStyleName("fuzzy-viewPort");

        initWidget(parent);

        vBar = new VBar();
        hBar = new HBar();
        square = new FPNGImage();
        square.setStyleName("fuzzy-square");

        vBar.addScrollListener(new FScrollListener() {

            public void onScroll(int offset) {
                viewPort.setWidgetPosition(child, -hBar.getScrollPosition(), -offset);
            }

        });

        hBar.addScrollListener(new FScrollListener() {

            public void onScroll(int offset) {
                viewPort.setWidgetPosition(child, -offset, -vBar.getScrollPosition());

            }

        });

        setViewPort(w);
        //addMouseWheelListener();
        setStyleName("fuzzy-FScrollPanel");
    }

    public void setViewPort(Widget w) {
        child = w;
        viewPort.add(child, 0, 0);
        FResizePoller resizePoller = new FResizePoller(child) {

            public void onResize(int w, int h) {
                updateGui(getOffsetWidth(), getOffsetHeight());
            }
        };
        resizePoller.startPolling(40);

    }

    public void setPixelSize(int w, int h) {
        super.setPixelSize(w, h);

        EventPreview eventPreview = new EventPreview() {

            public boolean onEventPreview(Event event) {
                return false;
            }
        };

        sinkEvents(Event.ONMOUSEDOWN | Event.ONMOUSEUP | Event.ONMOUSEMOVE | Event.ONMOUSEOUT | Event.ONMOUSEOVER | Event.ONMOUSEWHEEL);
        DOM.addEventPreview(eventPreview);

        updateGui(w, h);

        DOM.removeEventPreview(eventPreview);

    }

    public void setVerticalBarWidth(int w) {
        vBar.setVerticalBarWidth(w);
        updateGui(getOffsetWidth(), getOffsetHeight());
    }

    public void setHorizontalBarHeight(int h) {
        hBar.setHorizontalBarHeight(h);
        updateGui(getOffsetWidth(), getOffsetHeight());
    }

    public void setFixedHorizontalCursorSizeAndPosition(int w, int h, int x, int y) {
        hasHCursorFixedWidth = true;
        hBar.setFixedCursorSizeAndPosition(w, h, x, y);
    }

    public void setFixedVerticalCursorSizeAndPosition(int w, int h, int x, int y) {
        hasVCursorFixedHeight = true;
        vBar.setFixedCursorSizeAndPosition(w, h, x, y);
    }

    private void updateGui(int w, int h) {
        parent.add(viewPort);
        parent.add(hBar);
        parent.add(vBar);
        parent.add(square);

        hBar.setVisible(false);
        vBar.setVisible(false);
        square.setVisible(false);

        if (needHScroll() && needVScroll()) {

            hBar.setVisible(true);
            vBar.setVisible(true);
            square.setVisible(true);


            viewPort.setWidth((w - vBar.getArrowWidth()) + "px");

            viewPort.setHeight((h - hBar.getArrowHeight()) + "px");

            vBar.setHeight(viewPort.getOffsetHeight() + "px");
            vBar.setWidth(vBar.getArrowWidth() + "px");


            hBar.setWidth(viewPort.getOffsetWidth() + "px");
            hBar.setHeight(hBar.getArrowHeight() + "px");


            square.setPixelSize(vBar.getArrowWidth(), hBar.getArrowHeight());

            parent.setWidgetPosition(viewPort, 0, 0);
            parent.setWidgetPosition(vBar, viewPort.getOffsetWidth(), 0);
            parent.setWidgetPosition(hBar, 0, viewPort.getOffsetHeight());
            parent.setWidgetPosition(square, viewPort.getOffsetWidth(), viewPort.getOffsetHeight());

            if (child != null) {
                if (!hasVCursorFixedHeight)
                    vBar.setCursorHeight(child.getOffsetHeight());
                if (!hasHCursorFixedWidth)
                    hBar.setCursorWidth(child.getOffsetWidth());
            }
        } else if (needHScroll()) {

            hBar.setVisible(true);


            viewPort.setWidth(w + "px");
            viewPort.setHeight((h - hBar.getArrowHeight()) + "px");

            hBar.setWidth(viewPort.getOffsetWidth() + "px");
            hBar.setHeight(hBar.getArrowHeight() + "px");


            parent.setWidgetPosition(viewPort, 0, 0);
            parent.setWidgetPosition(hBar, 0, viewPort.getOffsetHeight());


            if (child != null)
                if (!hasHCursorFixedWidth)
                    hBar.setCursorWidth(child.getOffsetWidth());

            vBar.resetScrollPosition();

        } else if (needVScroll()) {
            vBar.setVisible(true);


            viewPort.setWidth((w - vBar.getArrowWidth()) + "px");
            viewPort.setHeight(h + "px");


            vBar.setHeight(viewPort.getOffsetHeight() + "px");
            vBar.setWidth(vBar.getArrowWidth() + "px");


            parent.setWidgetPosition(viewPort, 0, 0);
            parent.setWidgetPosition(vBar, viewPort.getOffsetWidth(), 0);


            if (child != null)
                if (!hasVCursorFixedHeight)
                    vBar.setCursorHeight(child.getOffsetHeight());

            hBar.resetScrollPosition();

        } else {

            viewPort.setWidth(w + "px");
            viewPort.setHeight(h + "px");

            parent.setWidgetPosition(viewPort, 0, 0);
            if (child != null)
                viewPort.setWidgetPosition(child, 0, 0);

            vBar.resetScrollPosition();
            hBar.resetScrollPosition();
        }
        addMouseWheelListener();
    }

    private boolean needHScroll() {


        if (parent.getOffsetWidth() >= child.getOffsetWidth())
            return false;

        return true;
    }

    private boolean needVScroll() {

        if (parent.getOffsetHeight() >= child.getOffsetHeight())
            return false;

        return true;
    }

    private void addMouseWheelListener() {
        FMouseWheelListener.setMouseWheelListener(this.getElement(), new FMouseWheelHandler() {

            public void onMouseWheelUp(int intensity) {
                vBar.handleWheelEvent(-intensity);
            }

            public void onMouseWheelDown(int intensity) {
                vBar.handleWheelEvent(intensity);
            }

        });

    }

    public void setVerticalUpArrowImageUrl(String url) {
        vBar.setUpArrowImageUrl(url);
    }

    public void setVerticalDownArrowImageUrl(String url) {
        vBar.setDownArrowImageUrl(url);
    }

    public void setHorizontalLeftArrowImageUrl(String url) {
        hBar.setLeftArrowImageUrl(url);
    }

    public void setHorizontalRightArrowImageUrl(String url) {
        hBar.setRightArrowImageUrl(url);
    }
}
